// Decompiled on 周六 2月 22 19:31:49 CST 2025 with Zomboid Decompiler v0.1.3 using Vineflower.
package zombie.network;

import java.util.ArrayList;
import zombie.characters.IsoPlayer;
import zombie.core.textures.ColorInfo;
import zombie.iso.IsoGridSquare;
import zombie.iso.LosUtil;

public class ServerLOS {
    public static ServerLOS instance;
    private ServerLOS.LOSThread thread;
    private ArrayList<ServerLOS.PlayerData> playersMain = new ArrayList();
    private ArrayList<ServerLOS.PlayerData> playersLOS = new ArrayList();
    private boolean bMapLoading = false;
    private boolean bSuspended = false;
    boolean bWasSuspended;

    private void noise(String var1) {
    }

    public static void init() {
        instance = new ServerLOS();
        instance.start();
    }

    public void start() {
        this.thread = new ServerLOS.LOSThread();
        this.thread.setName("LOS");
        this.thread.setDaemon(true);
        this.thread.start();
    }

    public void addPlayer(IsoPlayer player) {
        synchronized (this.playersMain) {
            if (this.findData(player) == null) {
                ServerLOS.PlayerData playerData = new ServerLOS.PlayerData(player);
                this.playersMain.add(playerData);
                synchronized (this.thread.notifier) {
                    this.thread.notifier.notify();
                }
            }
        }
    }

    public void removePlayer(IsoPlayer player) {
        synchronized (this.playersMain) {
            ServerLOS.PlayerData playerData = this.findData(player);
            this.playersMain.remove(playerData);
            synchronized (this.thread.notifier) {
                this.thread.notifier.notify();
            }
        }
    }

    public boolean isCouldSee(IsoPlayer player, IsoGridSquare sq) {
        ServerLOS.PlayerData playerData = this.findData(player);
        if (playerData != null) {
            int int0 = sq.x - playerData.px + 50;
            int int1 = sq.y - playerData.py + 50;
            if (int0 >= 0 && int0 < 100 && int1 >= 0 && int1 < 100) {
                return playerData.visible[int0][int1][sq.z];
            }
        }

        return false;
    }

    public void doServerZombieLOS(IsoPlayer player) {
        if (ServerMap.instance.bUpdateLOSThisFrame) {
            ServerLOS.PlayerData playerData = this.findData(player);
            if (playerData != null) {
                if (playerData.status == ServerLOS.UpdateStatus.NeverDone) {
                    playerData.status = ServerLOS.UpdateStatus.ReadyInMain;
                }

                if (playerData.status == ServerLOS.UpdateStatus.ReadyInMain) {
                    playerData.status = ServerLOS.UpdateStatus.WaitingInLOS;
                    this.noise("WaitingInLOS playerID=" + player.OnlineID);
                    synchronized (this.thread.notifier) {
                        this.thread.notifier.notify();
                    }
                }
            }
        }
    }

    public void updateLOS(IsoPlayer player) {
        ServerLOS.PlayerData playerData = this.findData(player);
        if (playerData != null) {
            if (playerData.status == ServerLOS.UpdateStatus.ReadyInLOS || playerData.status == ServerLOS.UpdateStatus.ReadyInMain) {
                if (playerData.status == ServerLOS.UpdateStatus.ReadyInLOS) {
                    this.noise("BusyInMain playerID=" + player.OnlineID);
                }

                playerData.status = ServerLOS.UpdateStatus.BusyInMain;
                player.updateLOS();
                playerData.status = ServerLOS.UpdateStatus.ReadyInMain;
                synchronized (this.thread.notifier) {
                    this.thread.notifier.notify();
                }
            }
        }
    }

    private ServerLOS.PlayerData findData(IsoPlayer isoPlayer) {
        for (int _int = 0; _int < this.playersMain.size(); _int++) {
            if (((ServerLOS.PlayerData)this.playersMain.get(_int)).player == isoPlayer) {
                return (ServerLOS.PlayerData)this.playersMain.get(_int);
            }
        }

        return null;
    }

    public void suspend() {
        this.bMapLoading = true;
        this.bWasSuspended = this.bSuspended;

        while (!this.bSuspended) {
            try {
                Thread.sleep(1L);
            } catch (InterruptedException interruptedException) {
            }
        }

        if (!this.bWasSuspended) {
            this.noise("suspend **********");
        }
    }

    public void resume() {
        this.bMapLoading = false;
        synchronized (this.thread.notifier) {
            this.thread.notifier.notify();
        }

        if (!this.bWasSuspended) {
            this.noise("resume **********");
        }
    }

    private class LOSThread extends Thread {
        public Object notifier = new Object();

        public void run() {
            while (true) {
                try {
                    this.runInner();
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }

        private void runInner() {
            MPStatistic.getInstance().ServerLOS.Start();
            synchronized (ServerLOS.this.playersMain) {
                ServerLOS.this.playersLOS.clear();
                ServerLOS.this.playersLOS.addAll(ServerLOS.this.playersMain);
            }

            for (int _int = 0; _int < ServerLOS.this.playersLOS.size(); _int++) {
                ServerLOS.PlayerData playerData = (ServerLOS.PlayerData)ServerLOS.this.playersLOS.get(_int);
                if (playerData.status == ServerLOS.UpdateStatus.WaitingInLOS) {
                    playerData.status = ServerLOS.UpdateStatus.BusyInLOS;
                    ServerLOS.this.noise("BusyInLOS playerID=" + playerData.player.OnlineID);
                    this.calcLOS(playerData);
                    playerData.status = ServerLOS.UpdateStatus.ReadyInLOS;
                }

                if (ServerLOS.this.bMapLoading) {
                    break;
                }
            }

            MPStatistic.getInstance().ServerLOS.End();

            while (this.shouldWait()) {
                ServerLOS.this.bSuspended = true;
                synchronized (this.notifier) {
                    try {
                        this.notifier.wait();
                    } catch (InterruptedException interruptedException) {
                    }
                }
            }

            ServerLOS.this.bSuspended = false;
        }

        private void calcLOS(ServerLOS.PlayerData playerData) {
            boolean _boolean = false;
            if (playerData.px == (int)playerData.player.getX()
                && playerData.py == (int)playerData.player.getY()
                && playerData.pz == (int)playerData.player.getZ()) {
                _boolean = true;
            }

            playerData.px = (int)playerData.player.getX();
            playerData.py = (int)playerData.player.getY();
            playerData.pz = (int)playerData.player.getZ();
            playerData.player.initLightInfo2();
            if (!_boolean) {
                byte _byte = 0;

                for (int int0 = 0; int0 < LosUtil.XSIZE; int0++) {
                    for (int int1 = 0; int1 < LosUtil.YSIZE; int1++) {
                        for (int int2 = 0; int2 < LosUtil.ZSIZE; int2++) {
                            LosUtil.cachedresults[int0][int1][int2][_byte] = 0;
                        }
                    }
                }

                try {
                    IsoPlayer.players[_byte] = playerData.player;
                    int int3 = playerData.px;
                    int int4 = playerData.py;

                    for (int int5 = -50; int5 < 50; int5++) {
                        for (int int6 = -50; int6 < 50; int6++) {
                            for (int int7 = 0; int7 < 8; int7++) {
                                IsoGridSquare isoGridSquare = ServerMap.instance.getGridSquare(int5 + int3, int6 + int4, int7);
                                if (isoGridSquare != null) {
                                    isoGridSquare.CalcVisibility(_byte);
                                    playerData.visible[int5 + 50][int6 + 50][int7] = isoGridSquare.isCouldSee(_byte);
                                    isoGridSquare.checkRoomSeen(_byte);
                                }
                            }
                        }
                    }
                } finally {
                    IsoPlayer.players[_byte] = null;
                }
            }
        }

        private boolean shouldWait() {
            if (ServerLOS.this.bMapLoading) {
                return true;
            } else {
                for (int _int = 0; _int < ServerLOS.this.playersLOS.size(); _int++) {
                    ServerLOS.PlayerData playerData = (ServerLOS.PlayerData)ServerLOS.this.playersLOS.get(_int);
                    if (playerData.status == ServerLOS.UpdateStatus.WaitingInLOS) {
                        return false;
                    }
                }

                synchronized (ServerLOS.this.playersMain) {
                    return ServerLOS.this.playersLOS.size() == ServerLOS.this.playersMain.size();
                }
            }
        }
    }

    private class PlayerData {
        public IsoPlayer player;
        public ServerLOS.UpdateStatus status = ServerLOS.UpdateStatus.NeverDone;
        public int px;
        public int py;
        public int pz;
        public boolean[][][] visible = new boolean[100][100][8];

        public PlayerData(IsoPlayer isoPlayer) {
            this.player = isoPlayer;
        }
    }

    public static final class ServerLighting implements IsoGridSquare.ILighting {
        private static final byte LOS_SEEN = 1;
        private static final byte LOS_COULD_SEE = 2;
        private static final byte LOS_CAN_SEE = 4;
        private static ColorInfo lightInfo = new ColorInfo();
        private byte los;

        @Override
        public int lightverts(int i) {
            return 0;
        }

        @Override
        public float lampostTotalR() {
            return 0.0F;
        }

        @Override
        public float lampostTotalG() {
            return 0.0F;
        }

        @Override
        public float lampostTotalB() {
            return 0.0F;
        }

        @Override
        public boolean bSeen() {
            return (this.los & 1) != 0;
        }

        @Override
        public boolean bCanSee() {
            return (this.los & 4) != 0;
        }

        @Override
        public boolean bCouldSee() {
            return (this.los & 2) != 0;
        }

        @Override
        public float darkMulti() {
            return 0.0F;
        }

        @Override
        public float targetDarkMulti() {
            return 0.0F;
        }

        @Override
        public ColorInfo lightInfo() {
            lightInfo.r = 1.0F;
            lightInfo.g = 1.0F;
            lightInfo.b = 1.0F;
            return lightInfo;
        }

        @Override
        public void lightverts(int i, int value) {
        }

        @Override
        public void lampostTotalR(float r) {
        }

        @Override
        public void lampostTotalG(float g) {
        }

        @Override
        public void lampostTotalB(float b) {
        }

        @Override
        public void bSeen(boolean seen) {
            if (seen) {
                this.los = (byte)(this.los | 1);
            } else {
                this.los &= -2;
            }
        }

        @Override
        public void bCanSee(boolean canSee) {
            if (canSee) {
                this.los = (byte)(this.los | 4);
            } else {
                this.los &= -5;
            }
        }

        @Override
        public void bCouldSee(boolean couldSee) {
            if (couldSee) {
                this.los = (byte)(this.los | 2);
            } else {
                this.los &= -3;
            }
        }

        @Override
        public void darkMulti(float f) {
        }

        @Override
        public void targetDarkMulti(float f) {
        }

        @Override
        public int resultLightCount() {
            return 0;
        }

        @Override
        public IsoGridSquare.ResultLight getResultLight(int index) {
            return null;
        }

        @Override
        public void reset() {
            this.los = 0;
        }
    }

    static enum UpdateStatus {
        NeverDone,
        WaitingInLOS,
        BusyInLOS,
        ReadyInLOS,
        BusyInMain,
        ReadyInMain;
    }
}
